#pragma once

#include<iostream>
#include<string>
#include<vector>
#include<functional>
#include <sys/types.h>
#include <sys/socket.h>
#include<pthread.h>

#include"InetAddr.hpp"
#include"ThreadPool.hpp"
#include"LockGuard"

using task_t=std::function<void()>;

class Route
{
public:
    Route()
    {
        pthread_mutex_init(&_mutex,nullptr);
    }
    void CheckOnlineUser(InetAddr &who)
    {
        LockGuard lock(&_mutex);
        for(auto& user:_online_user)
        {
            if(user==who)
            {
                LOG(DEBUG,"%s:%d is exists\n",who.Ip().c_str(),who.Port());
                return;
            }
        }
        LOG(DEBUG,"%s:%d add room\n",who.Ip().c_str(),who.Port());
        _online_user.push_back(who);
    }
    void Offline(InetAddr &who)
    {
        LockGuard lock(&_mutex);
        auto iter=_online_user.begin();
        for(;iter!=_online_user.end();iter++)
        {
            if(*iter==who)
            {
                LOG(DEBUG,"%s:%d offline\n",iter->Ip().c_str(),iter->Port());
                _online_user.erase(iter);
                break;//迭代器失效不建议继续循环
            }
        }
    }
    void ForwardHelper(int socketfd,const std::string message,InetAddr &who)
    {
        std::string send_message="["+who.Ip() +":"+ std::to_string(who.Port())+"]:" + message;
        LockGuard lock(&_mutex);
        for(auto &user:_online_user)
        {
            LOG(DEBUG,"forward message to [%s:%d]\n",user.Ip().c_str(),user.Port());
            struct sockaddr_in peer=user.Addr();
            sendto(socketfd,send_message.c_str(),send_message.size(),0,(struct sockaddr*)&peer,sizeof(peer));
        }
    }
    void Forward(int socketfd,const std::string &message,InetAddr &who)
    {
        CheckOnlineUser(who);
        if(message=="QUIT")
        {
            Offline(who);
        }
        // ForwardHelper(socketfd,message);
        task_t t=std::bind(&Route::ForwardHelper,this,socketfd,message,who);
        ThreadPool<task_t>::GetInstand()->Equeue(t);
    }
    ~Route()
    {
        pthread_mutex_destroy(&_mutex);
    }
private:
    std::vector<InetAddr> _online_user;
    pthread_mutex_t _mutex;
};